// Copyright (C) 2005 Taylor L. Riche <riche@cs.utexas.edu>
//  
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software 
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// $Id: pcaptools.cc 61 2005-07-28 17:01:05Z richetl $
//
// -----------------------------------------------------------------

#include "pcaptools.hh"

using namespace tt;

PcapReader::PcapReader(std::string fn) throw(std::invalid_argument) : TraceReader(fn)
{
  char error[256];
  
  pcapFile = pcap_open_offline(filename.c_str(), error);
  if(pcapFile == NULL) {
    throw std::invalid_argument("The input trace specified does not exist.");
  }
  return;
}

PcapReader::~PcapReader() 
{
  if(pcapFile != NULL) {
    pcap_close(pcapFile);
  }
  return;
}

void 
PcapReader::readPacket(Packet & newPacket) throw(std::underflow_error)
{
  const u_char * pcapPacketData;
  pcap_pkthdr pcapPacketInfo;
  
  pcapPacketData = pcap_next(pcapFile, &pcapPacketInfo);
  if(pcapPacketData == NULL) {
    throw std::underflow_error("Truncated pcap trace file.");
  }
  newPacket.tsSec = pcapPacketInfo.ts.tv_sec;
  newPacket.tsUSec = pcapPacketInfo.ts.tv_usec;
  //cerr << newPacket.tsSec << "\t" << newPacket.tsUSec << endl;
  memcpy(&newPacket.ipHdr, pcapPacketData + PCAP_DATA_OFFSET, sizeof(iphdr));
  memcpy(&newPacket.tcpHdr, pcapPacketData + PCAP_DATA_OFFSET + sizeof(iphdr),
	 sizeof(tcphdr));
  return;
}

PcapWriter::PcapWriter(std::string fn) throw(std::invalid_argument) : TraceWriter(fn)
{
  // should never get here!!
  pcap_t * pcapDummy = NULL;

  // but just in case
  throw std::invalid_argument("Do not yet support writing pcap files.");

  pcapFile = pcap_dump_open(pcapDummy, filename.c_str());
  if(pcapFile == NULL) {
    throw std::invalid_argument("There was an error opening the output file.");
  }
  return;
}

PcapWriter::~PcapWriter() 
{
  if(pcapFile != NULL) {
    pcap_dump_close(pcapFile);
  }
  return;
}

void 
PcapWriter::writePacket(const Packet & targetPacket)
{
  pcap_pkthdr pcapPacketInfo;
  u_char pcapPacketData[sizeof(iphdr) + sizeof(tcphdr) + PCAP_DATA_OFFSET];

  pcapPacketInfo.ts.tv_sec = targetPacket.tsSec;
  pcapPacketInfo.ts.tv_usec = targetPacket.tsUSec;
  for(int i = 0; i < PCAP_DATA_OFFSET; i++) {
    pcapPacketData[i] = 0;
  }
  memcpy(pcapPacketData + PCAP_DATA_OFFSET, &targetPacket.ipHdr, sizeof(iphdr) + sizeof(tcphdr));
  pcap_dump((u_char *)pcapFile, &pcapPacketInfo, pcapPacketData);
  return;
}
